]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOS9/Mac OS Test Searcher.c
mDNSResponder-161.1.tar.gz
[apple/mdnsresponder.git] / mDNSMacOS9 / Mac OS Test Searcher.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16
17 Change History (most recent first):
18
19 $Log: Mac\040OS\040Test\040Searcher.c,v $
20 Revision 1.23 2007/07/27 19:30:40 cheshire
21 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
22 to properly reflect tri-state nature of the possible responses
23
24 Revision 1.22 2006/08/14 23:24:29 cheshire
25 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
26
27 Revision 1.21 2004/12/16 20:49:34 cheshire
28 <rdar://problem/3324626> Cache memory management improvements
29
30 Revision 1.20 2004/10/19 21:33:18 cheshire
31 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
32 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
33 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
34
35 Revision 1.19 2004/09/17 01:08:50 cheshire
36 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
37 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
38 declared in that file are ONLY appropriate to single-address-space embedded applications.
39 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
40
41 Revision 1.18 2004/09/16 21:59:16 cheshire
42 For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
43
44 Revision 1.17 2004/06/10 04:37:27 cheshire
45 Add new parameter in mDNS_GetDomains()
46
47 Revision 1.16 2004/03/12 21:30:25 cheshire
48 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
49 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
50
51 Revision 1.15 2004/01/24 23:55:15 cheshire
52 Change to use mDNSOpaque16fromIntVal/mDNSVal16 instead of shifting and masking
53
54 Revision 1.14 2003/11/14 21:27:09 cheshire
55 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
56 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
57
58 Revision 1.13 2003/08/14 02:19:54 cheshire
59 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
60
61 Revision 1.12 2003/08/12 19:56:24 cheshire
62 Update to APSL 2.0
63
64 */
65
66 #include <stdio.h> // For printf()
67 #include <Events.h> // For WaitNextEvent()
68 #include <SIOUX.h> // For SIOUXHandleOneEvent()
69
70 #include "mDNSEmbeddedAPI.h" // Defines the interface to the client layer above
71 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
72
73 typedef struct
74 {
75 OTLIFO serviceinfolist;
76 Boolean headerPrinted;
77 Boolean lostRecords;
78 } SearcherServices;
79
80 typedef struct { ServiceInfo i; mDNSBool add; mDNSBool dom; OTLink link; } linkedServiceInfo;
81
82 // These don't have to be globals, but their memory does need to remain valid for as
83 // long as the search is going on. They are declared as globals here for simplicity.
84 #define RR_CACHE_SIZE 1000
85 static CacheEntity rrcachestorage[RR_CACHE_SIZE];
86 static mDNS mDNSStorage;
87 static mDNS_PlatformSupport PlatformSupportStorage;
88 static SearcherServices services;
89 static DNSQuestion browsequestion, domainquestion;
90
91 // PrintServiceInfo prints the service information to standard out
92 // A real application might want to do something else with the information
93 static void PrintServiceInfo(SearcherServices *services)
94 {
95 OTLink *link = OTReverseList(OTLIFOStealList(&services->serviceinfolist));
96
97 while (link)
98 {
99 linkedServiceInfo *ls = OTGetLinkObject(link, linkedServiceInfo, link);
100 ServiceInfo *s = &ls->i;
101
102 if (!services->headerPrinted)
103 {
104 printf("%-55s Type Domain IP Address Port Info\n", "Name");
105 services->headerPrinted = true;
106 }
107
108 if (ls->dom)
109 {
110 char c_dom[MAX_ESCAPED_DOMAIN_NAME];
111 ConvertDomainNameToCString(&s->name, c_dom);
112 if (ls->add) printf("%-55s available for browsing\n", c_dom);
113 else printf("%-55s no longer available for browsing\n", c_dom);
114 }
115 else
116 {
117 domainlabel name;
118 domainname type, domain;
119 char c_name[MAX_DOMAIN_LABEL+1], c_type[MAX_ESCAPED_DOMAIN_NAME], c_dom[MAX_ESCAPED_DOMAIN_NAME], c_ip[20];
120 DeconstructServiceName(&s->name, &name, &type, &domain);
121 ConvertDomainLabelToCString_unescaped(&name, c_name);
122 ConvertDomainNameToCString(&type, c_type);
123 ConvertDomainNameToCString(&domain, c_dom);
124 sprintf(c_ip, "%d.%d.%d.%d", s->ip.ip.v4.b[0], s->ip.ip.v4.b[1], s->ip.ip.v4.b[2], s->ip.ip.v4.b[3]);
125
126 printf("%-55s %-16s %-14s ", c_name, c_type, c_dom);
127 if (ls->add) printf("%-15s %5d %#s\n", c_ip, mDNSVal16(s->port), s->TXTinfo);
128 else printf("Removed\n");
129 }
130
131 link = link->fNext;
132 OTFreeMem(ls);
133 }
134 }
135
136 // When the name, address, port, and txtinfo for a service is found, FoundInstanceInfo()
137 // enqueues a record for PrintServiceInfo() to print.
138 // Note, a browsing application would *not* normally need to get all this information --
139 // all it needs is the name, to display to the user.
140 // Finding out the address, port, and txtinfo should be deferred to the time that the user
141 // actually needs to contact the service to use it.
142 static void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
143 {
144 SearcherServices *services = (SearcherServices *)query->ServiceInfoQueryContext;
145 linkedServiceInfo *info = (linkedServiceInfo *)(query->info);
146 if (query->info->ip.type == mDNSAddrType_IPv4)
147 {
148 mDNS_StopResolveService(m, query); // For this test code, one answer is sufficient
149 OTLIFOEnqueue(&services->serviceinfolist, &info->link);
150 OTFreeMem(query);
151 }
152 }
153
154 // When a new named instance of a service is found, FoundInstance() is called.
155 // In this sample code we turn around and immediately issue a query to resolve that service name to
156 // find its address, port, and txtinfo, but a normal browing application would just display the name.
157 static void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
158 {
159 #pragma unused (question)
160 SearcherServices *services = (SearcherServices *)question->QuestionContext;
161 linkedServiceInfo *info;
162
163 debugf("FoundInstance %##s PTR %##s", answer->name->c, answer->rdata->u.name.c);
164
165 if (answer->rrtype != kDNSType_PTR) return;
166 if (!services) { debugf("FoundInstance: services is NULL"); return; }
167
168 info = (linkedServiceInfo *)OTAllocMem(sizeof(linkedServiceInfo));
169 if (!info) { services->lostRecords = true; return; }
170
171 info->i.name = answer->rdata->u.name;
172 info->i.InterfaceID = answer->InterfaceID;
173 info->i.ip.type = mDNSAddrType_IPv4;
174 info->i.ip.ip.v4 = zerov4Addr;
175 info->i.port = zeroIPPort;
176 info->add = AddRecord;
177 info->dom = mDNSfalse;
178
179 if (!AddRecord) // If TTL == 0 we're deleting a service,
180 OTLIFOEnqueue(&services->serviceinfolist, &info->link);
181 else // else we're adding a new service
182 {
183 ServiceInfoQuery *q = (ServiceInfoQuery *)OTAllocMem(sizeof(ServiceInfoQuery));
184 if (!q) { OTFreeMem(info); services->lostRecords = true; return; }
185 mDNS_StartResolveService(m, q, &info->i, FoundInstanceInfo, services);
186 }
187 }
188
189 static void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
190 {
191 #pragma unused (m)
192 #pragma unused (question)
193 SearcherServices *services = (SearcherServices *)question->QuestionContext;
194 linkedServiceInfo *info;
195
196 debugf("FoundDomain %##s PTR %##s", answer->name->c, answer->rdata->u.name.c);
197
198 if (answer->rrtype != kDNSType_PTR) return;
199 if (!services) { debugf("FoundDomain: services is NULL"); return; }
200
201 info = (linkedServiceInfo *)OTAllocMem(sizeof(linkedServiceInfo));
202 if (!info) { services->lostRecords = true; return; }
203
204 info->i.name = answer->rdata->u.name;
205 info->i.InterfaceID = answer->InterfaceID;
206 info->i.ip.type = mDNSAddrType_IPv4;
207 info->i.ip.ip.v4 = zerov4Addr;
208 info->i.port = zeroIPPort;
209 info->add = AddRecord;
210 info->dom = mDNStrue;
211
212 OTLIFOEnqueue(&services->serviceinfolist, &info->link);
213 }
214
215 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
216 static Boolean YieldSomeTime(UInt32 milliseconds)
217 {
218 extern Boolean SIOUXQuitting;
219 EventRecord e;
220 WaitNextEvent(everyEvent, &e, milliseconds / 17, NULL);
221 SIOUXHandleOneEvent(&e);
222 return(SIOUXQuitting);
223 }
224
225 int main()
226 {
227 mStatus err;
228 Boolean DoneSetup = false;
229 void *tempmem;
230
231 SIOUXSettings.asktosaveonclose = false;
232 SIOUXSettings.userwindowtitle = "\pMulticast DNS Searcher";
233 SIOUXSettings.rows = 40;
234 SIOUXSettings.columns = 132;
235
236 printf("Multicast DNS Searcher\n\n");
237 printf("This software reports errors using MacsBug breaks,\n");
238 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
239 printf("******************************************************************************\n");
240
241 err = InitOpenTransport();
242 if (err) { debugf("InitOpenTransport failed %d", err); return(err); }
243
244 err = mDNS_Init(&mDNSStorage, &PlatformSupportStorage, rrcachestorage, RR_CACHE_SIZE,
245 mDNS_Init_DontAdvertiseLocalAddresses, mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
246 if (err) return(err);
247
248 // Make sure OT has a large enough memory pool for us to draw from at OTNotifier (interrupt) time
249 tempmem = OTAllocMem(0x10000);
250 if (tempmem) OTFreeMem(tempmem);
251 else printf("**** Warning: OTAllocMem couldn't pre-allocate 64K for us.\n");
252
253 services.serviceinfolist.fHead = NULL;
254 services.headerPrinted = false;
255 services.lostRecords = false;
256
257 while (!YieldSomeTime(35))
258 {
259 #if MDNS_ONLYSYSTEMTASK
260 // For debugging, use "#define MDNS_ONLYSYSTEMTASK 1" and call mDNSPlatformIdle() periodically.
261 // For shipping code, don't define MDNS_ONLYSYSTEMTASK, and you don't need to call mDNSPlatformIdle()
262 extern void mDNSPlatformIdle(mDNS *const m);
263 mDNSPlatformIdle(&mDNSStorage); // Only needed for debugging version
264 #endif
265 if (mDNSStorage.mDNSPlatformStatus == mStatus_NoError && !DoneSetup)
266 {
267 domainname srvtype, srvdom;
268 DoneSetup = true;
269 printf("\nSending mDNS service lookup queries and waiting for responses...\n\n");
270 MakeDomainNameFromDNSNameString(&srvtype, "_http._tcp.");
271 MakeDomainNameFromDNSNameString(&srvdom, "local.");
272 err = mDNS_StartBrowse(&mDNSStorage, &browsequestion, &srvtype, &srvdom, mDNSInterface_Any, mDNSfalse, FoundInstance, &services);
273 if (err) break;
274 err = mDNS_GetDomains(&mDNSStorage, &domainquestion, mDNS_DomainTypeBrowse, NULL, mDNSInterface_Any, FoundDomain, &services);
275 if (err) break;
276 }
277
278 if (services.serviceinfolist.fHead)
279 PrintServiceInfo(&services);
280
281 if (services.lostRecords)
282 {
283 services.lostRecords = false;
284 printf("**** Warning: Out of memory: Records have been missed.\n");
285 }
286 }
287
288 mDNS_StopBrowse(&mDNSStorage, &browsequestion);
289 mDNS_Close(&mDNSStorage);
290 return(0);
291 }